<?php

namespace Lib\Core;

class Pipe extends \Home {

	public $fifoPath;
	private $wPipe;
	private $rPipe;

	/**
	 * 自动创建一个管道.
	 *
	 * @param string  $name 管道名字.
	 * @param integer $mode 管道的权限，默认任何用户组可以读写.
	 */
	public function __construct($name = 'pipe', $mode = 0666) {
		$fifoPath = '/tmp/.' . $name . posix_getpid();
		if (!file_exists($fifoPath)) {
			if (!posix_mkfifo($fifoPath, $mode)) {
				$msg = 'create new pipe (' . $name . ') error.';
				$this->throwException($msg);
			}
		} else {
			$msg = 'pipe (' . $name . ') has exit.';
			$this->throwException($msg);
		}
		$this->fifoPath = $fifoPath;
	}

	public function write($data) {
		$fp = fopen($this->fifoPath, 'w');
		$content = fwrite($fp, $data);
		fclose($fp);
	}

	public function writeAll($data) {
		$this->wOpen();
		$wPipe = fopen($this->fifoPath, 'w');
		fwrite($wPipe, $data);
		fclose($wPipe);
	}

	public function closeWrite() {
		if ($this->wPipe) {
			fclose($this->wPipe);
		}
	}

	public function read($byte = 1024) {
		$this->openRead();
		return fread($this->rPipe, $byte);
	}

	public function readLine() {
		$this->openRead();
		$content = fgets($this->rPipe);
		return $content;
	}

	public function readAll() {
		if (!file_exists($this->fifoPath)) {
			return false;
		}
		$this->openRead();
		$rPipe = fopen($this->fifoPath, 'r');
		$data = '';
		while (!feof($rPipe)) {
			$data .= fread($rPipe, 1024);
		}
		fclose($rPipe);
		return $data;
	}

	public function closeRead() {
		if ($this->rPipe) {
			fclose($this->rPipe);
		}
	}

	/**
	 * 删除管道
	 *
	 * @return boolean is success
	 */
	public function rmPipe() {
		return unlink($this->fifoPath);
	}

	/**
	 * 读管道相关函数开始.
	 *
	 * @return boolean
	 */
	private function openRead() {
		$this->rPipe = fopen($this->fifoPath, 'r');
		if (!$this->rPipe) {
			$this->throwException('open pipe ' . $this->fifoPath . ' for read error.');
		}
	}

	/**
	 * 写管道函数开始.
	 *
	 * @return boolean
	 */
	public function wOpen() {
		if (!$this->wPipe) {
			$this->wPipe = fopen($this->fifoPath, 'w');
		}
	}

	private function throwException($msg, $code = 0) {
		$code = (int)$code;
		throw new \Lib\Exception\Pipe($msg, $code);
	}

	public function __destruct() {
		$this->closeRead();
		$this->closeWrite();
		$this->rmPipe();
	}
}